package mycompany.model.chat;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import mycompany.helper.HashHelper;
import mycompany.model.UserBaseModel;
import mycompany.model.message.MessageBaseModel;
import mycompany.service.ChatService;
import org.apache.log4j.Logger;

/**
 *
 * @author Volodymyr Lavrynovych <volodya.lavrynovych@gmail.com>
 */
public abstract class AbstractChatModel <U extends UserBaseModel, M extends MessageBaseModel> {
    
    protected static final Logger log = Logger.getLogger(ChatSimpleModel.class);
    protected String id;
    protected U owner;
    protected List<M> messages;
    protected List<U> users;
    protected boolean isActive = true;
    private boolean isGarbage = false;
    
    ChatService chatService = ChatService.getInstance();
    
    private final int maxNumberOfMessages;
    private final int maxNumberOfUsers;
    
    
    /**
     * Constructs an instance
     * @param ownerId defines user id which creates that chat
     */
    public AbstractChatModel(U owner, int maxNumberOfMessages, int maxNumberOfUsers){
        String generatedId = HashHelper.sha1(owner.getName()+new Date().getTime(), ""+new Date().getTime()+maxNumberOfMessages+maxNumberOfUsers).replace("=", "");
        generatedId = generatedId.replace("/", "").replace("+", ""); // special for stupid IE browsers
        this.id = generatedId;
        this.owner = owner;
        this.maxNumberOfMessages = maxNumberOfMessages;
        this.maxNumberOfUsers = maxNumberOfUsers;
        
        messages = new ArrayList<M>(maxNumberOfMessages);
        users = new ArrayList<U>();
        Collections.synchronizedList(messages);
        Collections.synchronizedList(users);
    }

    /**
     * Returns chat id
     * @return chat id
     */
    public String getId() {
        return id;
    }
    
    protected void markAsGarbage(){
        isGarbage = true;
    }

    public boolean isGarbage() {
        return isGarbage;
    }
    
    /**
     * Returns true if chat is active
     * @return true if chat is active
     */
    public boolean isActive() {
        return isActive;
    }
    
    /**
     * Returns owner id
     * @return owner id
     */
    public String getOwnerId() {
        return owner.getId();
    }

    public boolean isOwner(U user) {
        return owner.equals(user);
    }
    
    public boolean hasUser(U user){
        for(U user1 : users){
            if(user1.equals(user)) return true;
        }
        return false;
    }
    
    public abstract void addMessage(U user, String text);
    
    /**
     * Adds message
     * @param userId defines user id
     * @param text defines user text
     */
    protected void addMessageToList(M message, U user){
        synchronized(messages){
            if(hasUser(user)){
                if(messages.size()==maxNumberOfMessages){
                    messages.remove(0); //removes the oldest message in list
                }
                messages.add(message);
            }
        }
    }
    
    /**
     * Returns list of messages which starts from last readed
     * @param lastMessageId defines id of last readed message
     * @return list of messages which starts from last readed
     */
    public List<M> getNewMessages(long lastMessageId){
        List<M> result = new ArrayList<M>();
        for(M message : messages){
            if(message.getId()>lastMessageId) result.add(message);
        }
        
        Collections.sort(result);
        return result;
    }
    
    /**
     * Returns message by message id
     * @param id defines message id
     * @return message model
     * @throws Exception 
     */
    public M getMessageById(long id) {
        M result = null;
        for(M message : messages){
            if(message.getId()==id) result = message;
        }
        return result;
    }
    
    protected long getNextMessageId(){
        if(messages.isEmpty()) return 0;
        
        M message = messages.get(messages.size()-1);
        return message.getId()+1;
    }
    
    /**
     * Adds user
     * @param userId defines user id
     * @return true if user was added
     */
    public boolean addUser(U user) {
        boolean result = false;
        synchronized(users){
            if(users.size()==maxNumberOfUsers) return false;
            result = users.add(user);
        }
        return result;
    }
    
    /**
     * Removes user
     * @param userId defines user id
     * @return result of user removing
     */
    public boolean removeUser(U user){
        boolean result;
        synchronized(users){
            result = users.remove(user);
            if(users.isEmpty()) isActive = false;
        }
        return result;
    }
    
    public int getUserCount(){
        return users.size();
    }
    
    /**
     * Closes or opens chat if user is chat owner
     * @param user defines user which want to change status
     * @param status defines status of the chat activity
     */
    public void setActivityStatus(U user, boolean status){
        if(isOwner(user)) isActive = status;
    }
}
